package com.ssy.lingxi.contract.serviceimpl;

import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.model.dto.UserLoginCacheDTO;
import com.ssy.lingxi.common.response.PageData;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.contract.component.OfficeConvertService;
import com.ssy.lingxi.contract.constant.Constants;
import com.ssy.lingxi.contract.entity.ContractTemplate;
import com.ssy.lingxi.contract.model.bo.sign.ContractParamFillBO;
import com.ssy.lingxi.contract.model.constant.sign.ContractTemplateStateEnum;
import com.ssy.lingxi.contract.model.vo.sign.request.*;
import com.ssy.lingxi.contract.model.vo.sign.response.ContractTemplateListResponse;
import com.ssy.lingxi.contract.model.vo.sign.response.ContractTemplateResponse;
import com.ssy.lingxi.contract.model.vo.sign.response.ContractTemplateSelectResponse;
import com.ssy.lingxi.contract.model.vo.sign.response.PreviewContractTemplateResponse;
import com.ssy.lingxi.contract.repository.ContractTemplateRepository;
import com.ssy.lingxi.contract.service.IContractTemplateService;
import com.ssy.lingxi.contract.utils.ContractTemplateUtil;
import com.ssy.lingxi.contract.utils.FileUtils;
import com.ssy.lingxi.feign.UploadControllerFeign;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.persistence.criteria.Predicate;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 合同模板服务实现类
 *
 * @author yzc
 * @version 2.0.0
 * @date 2020/7/10
 */
@Slf4j
@Service
public class ContractTemplateServiceImpl implements IContractTemplateService {

    @Resource
    private ContractTemplateRepository contractTemplateRepository;
//    @Resource
//    private ContractParamRepository contractParamRepository;
    @Resource
    private OfficeConvertService officeConvertService;
    @Resource
    private UploadControllerFeign uploadControllerFeign;

    @Override
    public Wrapper<PageData<ContractTemplateListResponse>> pageContractTemplate(ContractTemplateListRequest request, UserLoginCacheDTO sysUser) {
        Pageable page = PageRequest.of(request.getCurrent() - 1, request.getPageSize(), Sort.by("id").ascending());

        Page<ContractTemplate> pageList = contractTemplateRepository.findAll((Specification<ContractTemplate>) (root, query, cb) -> {
            List<Predicate> predicateList = new ArrayList<>();
            predicateList.add(cb.equal(root.get("memberId"), sysUser.getMemberId()));
            if (Objects.nonNull(request.getName())) {
                predicateList.add(cb.like(root.get("name"), "%" + request.getName() + "%"));
            }
            return query.where(predicateList.toArray(new Predicate[0])).getRestriction();
        }, page);

        List<ContractTemplateListResponse> resultList = pageList.stream().map(e -> {
            ContractTemplateListResponse contractTemplateListResponse = new ContractTemplateListResponse();
            contractTemplateListResponse.setId(e.getId());
            contractTemplateListResponse.setName(e.getName());
            contractTemplateListResponse.setVersion(e.getVersion());
            contractTemplateListResponse.setDescription(e.getDescription());
            contractTemplateListResponse.setState(e.getState());
            return contractTemplateListResponse;
        }).collect(Collectors.toList());

        return Wrapper.success(new PageData<>(pageList.getTotalElements(), resultList));
    }

    @Override
    public Wrapper<ContractTemplateResponse> getContractTemplate(ContractTemplateIdRequest request) {
        ContractTemplate contractTemplate = contractTemplateRepository.findById(request.getId()).orElse(null);
        if (Objects.isNull(contractTemplate)) {
            return Wrapper.fail(ResponseCode.CONTRACT_DATA_RECORDS_DOES_NOT_EXIST);
        }

        ContractTemplateResponse contractTemplateResponse = new ContractTemplateResponse();
        contractTemplateResponse.setId(contractTemplate.getId());
        contractTemplateResponse.setName(contractTemplate.getName());
        contractTemplateResponse.setVersion(contractTemplate.getVersion());
        contractTemplateResponse.setDescription(contractTemplate.getDescription());
        contractTemplateResponse.setState(contractTemplate.getState());
        contractTemplateResponse.setFileExampleUrl(contractTemplate.getFileExampleUrl());
        contractTemplateResponse.setFileUrl(contractTemplate.getFileUrl());
        contractTemplateResponse.setFileExampleName(contractTemplate.getFileExampleName());
        contractTemplateResponse.setFileName(contractTemplate.getFileName());

        return Wrapper.success(contractTemplateResponse);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Wrapper<Void> addContractTemplate(ContractTemplateRequest request, UserLoginCacheDTO sysUser) {
        // 保存合同模板信息
        ContractTemplate contractTemplate = new ContractTemplate();
        contractTemplate.setName(request.getName());
        contractTemplate.setVersion(request.getVersion());
        contractTemplate.setDescription(request.getDescription());
        contractTemplate.setState(ContractTemplateStateEnum.ENABLE.getCode());
        contractTemplate.setFileExampleUrl(request.getFileExampleUrl());
        contractTemplate.setFileExampleName(request.getFileExampleName());
        contractTemplate.setFileName(request.getFileName());
        contractTemplate.setFileUrl(request.getFileUrl());
        contractTemplate.setMemberId(sysUser.getMemberId());
        contractTemplate.setRoleId(sysUser.getMemberRoleId());
        contractTemplate.setCreateTime(System.currentTimeMillis());

        contractTemplateRepository.saveAndFlush(contractTemplate);

        return Wrapper.success();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Wrapper<Void> updateContractTemplate(ContractTemplateRequest request, UserLoginCacheDTO sysUser) {
        ContractTemplate contractTemplate = contractTemplateRepository.findByIdAndMemberId(request.getId(), sysUser.getMemberId()).orElse(null);
        if (Objects.isNull(contractTemplate)) {
            return Wrapper.fail(ResponseCode.CONTRACT_DATA_RECORDS_DOES_NOT_EXIST);
        }

        contractTemplate.setName(request.getName());
        contractTemplate.setVersion(request.getVersion());
        contractTemplate.setDescription(request.getDescription());
        contractTemplate.setFileUrl(request.getFileUrl());
        contractTemplate.setFileName(request.getFileName());

        contractTemplateRepository.saveAndFlush(contractTemplate);

        return Wrapper.success();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Wrapper<Void> updateStatusContractTemplate(ContractTemplateStateRequest request, UserLoginCacheDTO sysUser) {
        ContractTemplate contractTemplate = contractTemplateRepository.findByIdAndMemberId(request.getId(), sysUser.getMemberId()).orElse(null);
        if (Objects.isNull(contractTemplate)) {
            return Wrapper.fail(ResponseCode.CONTRACT_DATA_RECORDS_DOES_NOT_EXIST);
        }

        if (StringUtils.isBlank(contractTemplate.getFileUrl())) {
            return Wrapper.fail(ResponseCode.CONTRACT_READ_CONTRACT_FAIL);
        }

        contractTemplate.setState(request.getState());
        contractTemplateRepository.saveAndFlush(contractTemplate);

        return Wrapper.success();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Wrapper<Void> deleteContractTemplate(ContractTemplateIdRequest request, UserLoginCacheDTO sysUser) {
        ContractTemplate contractTemplate = contractTemplateRepository.findByIdAndMemberId(request.getId(), sysUser.getMemberId()).orElse(null);
        if (Objects.isNull(contractTemplate)) {
            return Wrapper.fail(ResponseCode.CONTRACT_DATA_RECORDS_DOES_NOT_EXIST);
        }

        if (ContractTemplateStateEnum.ENABLE.getCode().equals(contractTemplate.getState())) {
            return Wrapper.fail(ResponseCode.CONTRACT_STATUS_MISMATCH);
        }

        contractTemplateRepository.deleteById(contractTemplate.getId());

        return Wrapper.success();
    }

    @Override
    public Wrapper<List<ContractTemplateSelectResponse>> listContractTemplate(UserLoginCacheDTO sysUser) {
        List<ContractTemplate> all = contractTemplateRepository.findAllByMemberIdAndState(sysUser.getMemberId(), ContractTemplateStateEnum.ENABLE.getCode(), Sort.by("id").descending());
        List<ContractTemplateSelectResponse> resultList = all.stream().map(e -> {
            ContractTemplateSelectResponse contractTemplateSelectResponse = new ContractTemplateSelectResponse();
            contractTemplateSelectResponse.setId(e.getId());
            contractTemplateSelectResponse.setName(e.getName());
            contractTemplateSelectResponse.setVersion(e.getVersion());
            return contractTemplateSelectResponse;
        }).collect(Collectors.toList());

        return Wrapper.success(resultList);
    }

    @Override
    public Wrapper<PreviewContractTemplateResponse> previewContractTemplate(PreviewContractTemplateRequest request) {
        // 获取合同模板文件信息
        byte[] bytes = FileUtils.fileDownload(request.getContractUrl());
        if (bytes.length <= 0) {
            throw new BusinessException(ResponseCode.CONTRACT_READ_CONTRACT_FAIL);
        }

        // 填充合同参数
        ContractParamFillBO paramFillBO = ContractParamFillBO.build();
        byte[] docBytes = ContractTemplateUtil.fillContractTemplate(bytes, paramFillBO);
        if (Objects.isNull(docBytes)) {
            return Wrapper.fail(ResponseCode.CONTRACT_FILL_CONTRACT_FAIL);
        }

        // word转pdf
        byte[] pdfBytes;
        try {
            // 转换
            ByteArrayInputStream docbais = new ByteArrayInputStream(docBytes);
            ByteArrayOutputStream pdfbaos = new ByteArrayOutputStream();
            officeConvertService.convert(docbais, pdfbaos, Constants.contract_file_doc_suffix, Constants.contract_file_pdf_suffix);

            pdfBytes = pdfbaos.toByteArray();
        } catch (Exception e) {
            log.error("word转pdf失败", e);
            throw new BusinessException(ResponseCode.CONTRACT_WORD_TO_PDF_FAIL);
        }

        // 上传oss
        MultipartFile multipartFile = FileUtils.createMultipartFile(pdfBytes, Constants.contract_file_pdf_suffix);
        Wrapper<String> upload = uploadControllerFeign.upload(multipartFile);
        if (ResponseCode.SUCCESS.getCode() != upload.getCode()) {
            return Wrapper.fail(ResponseCode.UPLOADED_FILE_FORMAT_ERROR);
        }

        PreviewContractTemplateResponse response = new PreviewContractTemplateResponse();
        response.setContractName(request.getContractName());
        response.setContractUrl(upload.getData());

        return Wrapper.success(response);
    }
}